#include "androidqqcore.h"

AndroidQQCore::AndroidQQCore(QObject *parent):QObject(parent)
{
    RegisterCmdPackClass();
    RegisterSolvers();
    connect(&socket,&QTcpSocket::connected,this,&AndroidQQCore::onConnected);
    connect(&socket,&QTcpSocket::disconnected,this,&AndroidQQCore::disconnected);
    connect(&socket,&QTcpSocket::readyRead,this,&AndroidQQCore::readyRead);
    connect(&timeHeart,&QTimer::timeout,this,&AndroidQQCore::runHeartBeat);
    socket.setSocketOption(QTcpSocket::SocketOption::KeepAliveOption,1);
    socket.setParent(this);//set eventloop parent
}

AndroidQQCore::~AndroidQQCore()
{
    timeHeart.stop();
    socket.abort();
}

void AndroidQQCore::registerClass()
{
    qmlRegisterType<AndroidQQCore>("AndroidQQCore",1,0,"AndroidQQCore");
}

void AndroidQQCore::connnectToHost()
{
    socket.abort();
    socket.connectToHost("113.96.13.208",8080);
}
/*
void AndroidQQCore::setQmlContext(QQmlContext *context)
{
    AndroidQQCore::context = context;
}
*/
void AndroidQQCore::login(uint uin, QString password)
{
    if(!checkState())return;
    socket.write(factory.Login(uin,password,NetworkType::WIFI));
}

void AndroidQQCore::getGroupList()
{
    if(!checkState())return;
    socket.write(factory.GetTroopListReqV2Simplify(loginSigInfo));
}

void AndroidQQCore::getFriendList()
{
    if(!checkState())return;
    socket.write(factory.GetFriendList(loginSigInfo));
}

void AndroidQQCore::getMessage()
{
    socket.write(factory.GetMessage(loginSigInfo));
}

void AndroidQQCore::sendMessageToGroup(qint64 groupCode, QString content)
{
    if(!checkState())return;
    if(content == "")return;
    socket.write(factory.SendMessageToGroup(loginSigInfo,groupCode,content));
}

void AndroidQQCore::sendMessageToFriend(qint64 uin, QString content)
{
    if(!checkState())return;
    if(content == "")return;
    socket.write(factory.SendMessageToFriend(loginSigInfo,uin,content));
}

void AndroidQQCore::callback_wtlogin_login(RecvPacket &recvPacket, QVariantMap &ret)
{
    if(recvPacket.bodyObject == nullptr)return;
    ret["type"] = MessageType::Login;
    wtlogin_login * packet = (wtlogin_login*)recvPacket.bodyObject;

    ret["LoginResponse"] = packet->loginResponse;
    if(packet->loginResponse == LoginResponse::LoginSuccess){
        loginSigInfo = packet->tlvSolver0x119.loginSigInfo;
        loginSigInfo.uin = recvPacket.uinString.toUInt();
        loginSigInfo.simpleInfo.uin = loginSigInfo.uin;
        ret["nick"] = loginSigInfo.simpleInfo.nick;
        socket.write(factory.StatSvcRegister(loginSigInfo,OnlineStatus::ONLINE));
    }else if(packet->loginResponse == LoginResponse::UnsafeDeviceLogin){
        qDebug()<<packet->deviceLockUrl;
    }
}

void AndroidQQCore::callback_StatSvc_register(RecvPacket &recvPacket, QVariantMap &ret)
{
    //TODO UNIMPLEMENT
    ret["type"] = MessageType::StatSvcReg;
    if(!timeHeart.isActive())timeHeart.start(60000);
    //socket.write(factory.GetTroopListReqV2Simplify(loginSigInfo));
    //socket.write(factory.GetMessage(loginSigInfo));
}

void AndroidQQCore::callback_ConfigPushSvc_PushReq(RecvPacket &recvPacket, QVariantMap &ret)
{
    //qDebug()<<recvPacket.ssoFrame->ssoSequenceId<<recvPacket.ssoFrame->outgoingPacketSessionId;
    socket.write(factory.ConfigPushSvcPushResp(loginSigInfo,recvPacket.ssoFrame->ssoSequenceId));
}

void AndroidQQCore::callback_Heartbeat_Alive(RecvPacket &recvPacket, QVariantMap &ret)
{
    haveHeartRsp = true;
    ret["type"] = MessageType::HeartBeat;
}

void AndroidQQCore::callback_MessageSvc_PushForceOffline(RecvPacket &recvPacket, QVariantMap &ret)
{
    timeHeart.stop();//todo error to stop
    ret["type"] = MessageType::ForceOffline;
}

void AndroidQQCore::callback_friendlist_GetTroopListReqV2(RecvPacket &recvPacket, QVariantMap &ret)
{
    ret["type"] = MessageType::GetTroopListReqV2;
    ret["group"] = ((friendlist_GetTroopListReqV2 *)recvPacket.bodyObject)->groupData;
}

void AndroidQQCore::callback_MessageSvc_PbSendMsg(RecvPacket &recvPacket, QVariantMap &ret)
{
    ret["type"] = MessageType::SendMsgRep;
    ret["result"] = ((MessageSvc_PbSendMsg *)recvPacket.bodyObject)->result;
}

void AndroidQQCore::callback_OnlinePush_PbPushGroupMsg(RecvPacket &recvPacket, QVariantMap &ret)
{
    ret["type"] = MessageType::GroupMessgae;
    const auto &groupMsg = ((OnlinePush_PbPushGroupMsg *)recvPacket.bodyObject)->pbPushMsg;
    ret["Nick"] = QString::fromStdString(groupMsg.msg().msghead().groupinfo().groupcard());
    ret["Uin"] = (qint64)groupMsg.msg().msghead().fromuin();
    ret["groupName"] = QString::fromStdString(groupMsg.msg().msghead().groupinfo().groupname());
    ret["groupCode"] = (qint64)groupMsg.msg().msghead().groupinfo().groupcode();
    QString tmp;
    for(int i=0;i<groupMsg.msg().msgbody().richtext().elems_size();++i)
        tmp += QString::fromStdString(groupMsg.msg().msgbody().richtext().elems(i).text().str());
    ret["message"] = tmp;
    ret["img"] = QString::fromStdString(groupMsg.msg().msgbody().richtext().elems(0).customface().origurl());
    ret["width"] = (int)groupMsg.msg().msgbody().richtext().elems(0).customface().width();
    ret["height"] = (int)groupMsg.msg().msgbody().richtext().elems(0).customface().height();
}

void AndroidQQCore::callback_MessageSvc_PushNotify(RecvPacket &recvPacket, QVariantMap &ret)
{
    socket.write(factory.GetMessage(loginSigInfo));
}

void AndroidQQCore::callback_friendlist_getFriendGroupList(RecvPacket &recvPacket, QVariantMap &ret)
{
    ret["type"] = MessageType::FriendList;
    ret["friends"] = ((friendlist_getFriendGroupList *)recvPacket.bodyObject)->friendList;
}

void AndroidQQCore::callback_MessageSvc_PbGetMsg(RecvPacket &recvPacket, QVariantMap &ret)
{
    ret["type"] = MessageType::FriendMessage;
    const auto & tmp = ((MessageSvc_PbGetMsg *)recvPacket.bodyObject)->resp;
    QVariantList list;
    if(tmp.msgrsptype() != 0){
        //update sync cookie
        //if do not,it cant recv
        loginSigInfo.c2cMessageSyncData.msgCtrlBuf = QByteArray::fromStdString(tmp.msgctrlbuf());
        loginSigInfo.c2cMessageSyncData.pubAccountCookie = QByteArray::fromStdString(tmp.pubaccountcookie());
        loginSigInfo.c2cMessageSyncData.syncCookie = QByteArray::fromStdString(tmp.synccookie());
        if(tmp.syncflag() == qqprotobuf::MsgSvc::SyncFlag::CONTINUE){
            socket.write(factory.GetMessage(loginSigInfo,qqprotobuf::MsgSvc::SyncFlag::CONTINUE));
        }
        //continue to get message

        for(int i=0;i<tmp.uinpairmsgs_size();++i){
            const auto & msgs = tmp.uinpairmsgs(i);
            for(int j=0;j<msgs.msg_size();++j){
                const auto & msg = msgs.msg(j);
                switch (msg.msghead().msgtype()) {
                case 33:break;//unimplement
                case 166:{
                    QVariantMap item;
                    item["Uin"] = (qint64)msg.msghead().fromuin();
                    const auto & elem = msg.msgbody().richtext().elems(0);
                    //item["img"] = QString::fromStdString(elem.customface().origurl());
                    //item["height"] = elem.customface().height();
                    //item["width"] = elem.customface().width();
                    item["img"] = QString::fromStdString(elem.notonlineimage().origurl());
                    item["height"] = elem.notonlineimage().picheight();
                    item["width"] = elem.notonlineimage().picwidth();
                    item["message"] = QString::fromStdString(elem.text().str());
                    //qDebug()<<QString::fromStdString(elem.text().str());
                    list.append(item);
                }break;
                default:qDebug()<<"Unknow Message Type"<<msg.msghead().msgtype();
                }
            }
        }
    }
    ret["content"] = list;
}

void AndroidQQCore::callback_OnlinePush_ReqPush(RecvPacket &recvPacket, QVariantMap &ret)
{

}

void AndroidQQCore::callback_ConfigPushSvc_PushDomain(RecvPacket &recvPacket, QVariantMap &ret)
{

}

bool AndroidQQCore::checkState()
{
    return socket.state() == QTcpSocket::ConnectedState;
}

void AndroidQQCore::runHeartBeat()
{
    if(!haveHeartRsp){
        //i am died.
        qDebug()<<"no heartBeat response.";
        emit disconnected();
    }
    socket.write(factory.HeartbeatAlive(loginSigInfo));
    haveHeartRsp = false;
}

void AndroidQQCore::callbackThis(QString funcName, RecvPacket &recvPacket, QMap<QString, QVariant> &ret)
{
    //WARN MAYBE IT'S MULTITHREAD UNSAFE
    //BECAUSE IT WRITE RET .
    bool tmp = QMetaObject::invokeMethod(this,funcName.toLatin1(),Qt::DirectConnection,Q_ARG(RecvPacket&,recvPacket),Q_ARG(QVariantMap&,ret));
    qDebug()<<"CALLBACK"<<funcName<<tmp<<"androidqqcore.cpp";
}

void AndroidQQCore::onConnected()
{
    if(loginSigInfo.uin != 0)socket.write(factory.StatSvcRegister(loginSigInfo,OnlineStatus::ONLINE));
    //register the state again.
    qDebug()<<"onConnected";
    QVariantMap ret;
    ret["type"] = MessageType::ConnectedServer;
    emit message(ret);
}

void AndroidQQCore::readyRead()
{
    recvBuffer.append(socket.readAll());
    if(recvLength == 0 && recvBuffer.size() != 0)recvLength = Util::getData<int>(recvBuffer);
    qDebug()<<"readyRead"<<recvLength<<recvBuffer.size();
    if(recvBuffer.length() < recvLength)return;
    RecvPacket recvPacket(recvBuffer.mid(0,recvLength),loginSigInfo.d2Key);
    loginSigInfo.outgoingPacketSessionId = recvPacket.ssoFrame->outgoingPacketSessionId;
    recvBuffer = recvBuffer.right(recvBuffer.size() - recvLength);
    recvLength = 0;
    QVariantMap ret;
    if(recvPacket.ssoFrame != nullptr)callbackThis("callback_"+recvPacket.ssoFrame->commandName,recvPacket,ret);
    emit message(ret);
}

void AndroidQQCore::disconnected()
{
    timeHeart.stop();
    qDebug()<<"Disconnected";
    QVariantMap ret;
    ret["type"] = MessageType::DisConnectedServer;
    emit message(ret);
}
